package web

import (
	"context"
	"fmt"
	"gitee.com/jmesyan/mqant/examples/helloworld/rpctest"
	rpcpb "gitee.com/jmesyan/mqant/rpc/pb"
	"github.com/golang/protobuf/proto"
	"io"
	"net/http"
	"sync"
	"time"

	"gitee.com/jmesyan/mqant/conf"
	"gitee.com/jmesyan/mqant/log"
	"gitee.com/jmesyan/mqant/module"
	basemodule "gitee.com/jmesyan/mqant/module/base"
	"gitee.com/jmesyan/mqant/registry"
	mqrpc "gitee.com/jmesyan/mqant/rpc"
	"gitee.com/jmesyan/mqant/selector"
	"k8s.io/apimachinery/pkg/util/rand"
)

var Module = func() module.Module {
	this := new(Web)
	return this
}

type Web struct {
	basemodule.BaseModule
}

func (self *Web) GetType() string {
	//很关键,需要与配置文件中的Module配置对应
	return "Web"
}
func (self *Web) Version() string {
	//可以在监控时了解代码版本
	return "1.0.0"
}
func (self *Web) OnInit(app module.App, settings *conf.ModuleSettings) {
	self.BaseModule.OnInit(self, app, settings)
	//_ = app.GetSettings().Settings["sadsd"].(string)
	//_ = self.GetModuleSettings().Settings["port"].(int)

}

func (self *Web) startHttpServer() *http.Server {
	srv := &http.Server{Addr: ":8080"}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_ = r.ParseForm()
		ctx, _ := context.WithTimeout(context.TODO(), time.Second*3)
		rstr, err := mqrpc.String(
			self.RpcCall(
				// context.Background(),
				ctx,
				"helloworld",
				"/say/hi",
				mqrpc.Param(r.Form.Get("name")),
				selector.WithStrategy(func(services []*registry.Service) selector.Next {
					var nodes []*registry.Node
					for _, service := range services {
						for _, node := range service.Nodes {
							// if node.Metadata["version"] == "1.0.0" {
							nodes = append(nodes, node)
							// }
						}
					}
					var mtx sync.Mutex
					return func() (*registry.Node, error) {
						mtx.Lock()
						defer mtx.Unlock()
						if len(nodes) == 0 {
							return nil, fmt.Errorf("no node")
						}
						index := rand.Intn(len(nodes))
						return nodes[index], nil
					}
				}),
			),
		)
		log.Info("RpcCall %v , err %v", rstr, err)
		_, _ = io.WriteString(w, rstr)
	})
	http.HandleFunc("/test/proto", func(w http.ResponseWriter, r *http.Request) {
		_ = r.ParseForm()
		ctx, _ := context.WithTimeout(context.TODO(), time.Second*3)
		protobean := new(rpcpb.ResultInfo)
		err := mqrpc.Proto(protobean, func() (reply interface{}, errstr interface{}) {
			return self.RpcCall(
				ctx,
				"rpctest",     //要访问的moduleType
				"/test/proto", //访问模块中handler路径
				mqrpc.Param(&rpcpb.ResultInfo{Error: *proto.String(r.Form.Get("message"))}),
			)
		})
		log.Info("RpcCall %v , err %v", protobean, err)
		if err != nil {
			_, _ = io.WriteString(w, err.Error())
		}
		_, _ = io.WriteString(w, protobean.Error)
	})
	http.HandleFunc("/test/marshal", func(w http.ResponseWriter, r *http.Request) {
		_ = r.ParseForm()
		ctx, _ := context.WithTimeout(context.TODO(), time.Second*3)
		rspbean := new(rpctest.Rsp)
		err := mqrpc.Marshal(rspbean, func() (reply interface{}, errstr interface{}) {
			return self.RpcCall(
				ctx,
				"rpctest@mynode001", //要访问的moduleType
				"/test/marshal",     //访问模块中handler路径
				mqrpc.Param(&rpctest.Req{Id: "hello 我是RpcInvoke"}),
			)
		})
		log.Info("RpcCall %v , err %v", rspbean, err)
		if err != nil {
			_, _ = io.WriteString(w, err.Error())
		}
		_, _ = io.WriteString(w, rspbean.Msg)
	})

	go func() {
		if err := srv.ListenAndServe(); err != nil {
			// cannot panic, because this probably is an intentional close
			log.Info("Httpserver: ListenAndServe() error: %s", err)
		}
	}()
	// returning reference so caller can call Shutdown()
	return srv
}

func (self *Web) Run(closeSig chan bool) {
	log.Info("web: starting HTTP server :8080")
	srv := self.startHttpServer()
	<-closeSig
	log.Info("web: stopping HTTP server")
	// now close the server gracefully ("shutdown")
	// timeout could be given instead of nil as a https://golang.org/pkg/context/
	if err := srv.Shutdown(nil); err != nil {
		panic(err) // failure/timeout shutting down the server gracefully
	}
	log.Info("web: done. exiting")
}

func (self *Web) OnDestroy() {
	//一定别忘了关闭RPC
	_ = self.GetServer().OnDestroy()
}
